﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;

namespace CoderJoe.WoW.GearManager
{
	class PropertyStore
	{
		protected ISynchronizeInvoke InvokeOwner { get; set; }
		private Dictionary<string, object> State { get; set; }
		private Action<PropertyChangedEventArgs> ChangedHandler { get; set; }
		private Action<PropertyChangingEventArgs> ChangingHandler { get; set; }

		public PropertyStore(
			Action<PropertyChangedEventArgs> changedHandler,
			Action<PropertyChangingEventArgs> changingHandler)
		{
			ChangedHandler = changedHandler;
			ChangingHandler = changingHandler;
			State = new Dictionary<string, object>();
			SetInvokeOwner(null);
		}

		public void SetInvokeOwner(ISynchronizeInvoke invoker)
		{
			if (invoker == null)
				InvokeOwner = new MockInvoker();
			else
				InvokeOwner = invoker;
		}

		public TResult GetValue<TResult>(string propertyName, TResult defaultValue)
		{
			object result =
				(from kvp in State
				 where kvp.Key == propertyName
				 select kvp.Value).FirstOrDefault();

			if (result == null)
				return defaultValue;
			else
				return (TResult)result;
		}

		public void SetValue<TResult>(string propertyName, TResult value)
		{
			if (InvokeOwner.InvokeRequired == false)
			{
				if (ChangingHandler != null)
				{
					PropertyChangingEventArgs args = new PropertyChangingEventArgs(propertyName);
					ChangingHandler(args);
				}

				State[propertyName] = value;

				if (ChangedHandler != null)
				{
					PropertyChangedEventArgs args = new PropertyChangedEventArgs(propertyName);
					ChangedHandler(args);
				}
			}
			else
			{
				InvokeOwner.Invoke(new Action<string, TResult>(SetValue<TResult>),
					new object[]{ propertyName, value});
			}
		}

		internal void Clear()
		{
			string[] keys = State.Keys.ToArray();
			foreach (string value in keys)
			{
				SetValue<object>(value, null);
			}
			State.Clear();
		}
	}

	internal class MockInvoker
	: ISynchronizeInvoke
	{

		#region ISynchronizeInvoke Members

		IAsyncResult ISynchronizeInvoke.BeginInvoke(Delegate method, object[] args)
		{
			throw new NotImplementedException();
		}

		object ISynchronizeInvoke.EndInvoke(IAsyncResult result)
		{
			throw new NotImplementedException();
		}

		object ISynchronizeInvoke.Invoke(Delegate method, object[] args)
		{
			throw new NotImplementedException();
		}

		bool ISynchronizeInvoke.InvokeRequired
		{
			get { return false; }
		}

		#endregion
	}
}
